home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / commands / ls.c < prev    next >
C/C++ Source or Header  |  1990-07-23  |  23KB  |  807 lines

  1. /* ls - list files            Author: Peter Housel */
  2.  
  3. /*@*Introduction.
  4.  * This file is part of \fIls\fP for Minix. It was written in the spring
  5.  * of 1989 by Peter S. Housel. This program is in the public domain and may
  6.  * be redistributed without restriction. As such, no warranty of any kind
  7.  * is provided.
  8.  * .PP
  9.  * The following changes to the program have been made:
  10.  * .IP \(bu
  11.  * Version 1.1 - removed references to \fB\-q\fP option, added |ONECOLUMN|
  12.  * and other compile-time options.
  13.  */
  14.  
  15. /*@ \fILs\fP is a version of standard Minix directory listing program. Because
  16.  * it use so often used, it should be as fast as possible. It should be
  17.  * somewhat "featureful" (Rob Pike nonwithstanding), but not in a way
  18.  * that interferes with its use as a "software tool." It should take
  19.  * up a small to medium amount of memory.
  20.  * .PP
  21.  * The program should be compiled using:
  22.  * .nf
  23.  *    \fBcc -o ls -D_MINIX -D_POSIX_SOURCE ls.c
  24.  *    chmem =4096 ls\fP
  25.  * or
  26.  *    \fBcc -o ls -DATARI_ST ls.c\fP
  27.  * .fi
  28.  * If you do not want multi-column listings to be the default when
  29.  * standard output is a tty, define |ONECOLUMN| (by adding
  30.  * \fB\-DONECOLUMN\fP to the compile flags). Similarly, |NFILE|,
  31.  * |STRINGSPACE|, and |LINEWIDTH| can be changed with appropriate
  32.  * predefines.
  33.  */
  34.  
  35. #define ONECOLUMN        /* default is 1 column listings */
  36. #define major(x) ( (x>>8) & 0377)
  37. #define minor(x) (x & 0377)
  38.  
  39. /*@ Since \fIls\fP has to know a lot about files, there are quite a few
  40.  * headers to include.
  41.  */
  42. #include <sys/types.h>
  43. #include <sys/stat.h>
  44. #include <errno.h>
  45. #include <limits.h>
  46. #include <dirent.h>
  47. #include <pwd.h>
  48. #include <grp.h>
  49. #include <time.h>
  50. #include <stdio.h>
  51.  
  52. extern int errno;
  53.  
  54. /*@ |DOTDIR()| determines whether or not a given |name| is one of the
  55.  * special directory files "." or "..".
  56.  */
  57. #define DOTDIR(name)    \
  58.   (name[0] == '.'    \
  59.    && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
  60.  
  61. /*@ We use |getopt()| to parse the command-line flag arguments. This
  62.  * annoys some people who are used to the (BSD pre-Tahoe release)
  63.  * "infinte args \fIls\fP" that doesn't complain about anything.
  64.  */
  65. extern int getopt(     /* int argc, char **argv, char *optstring */ );
  66. extern char *optarg;
  67. extern int optind;
  68.  
  69. /*@ It may be necessary to |stat()| each file that is listed.
  70.  * The toplevel files (specified by the arguments) will need to be, to
  71.  * determine which ones are directories. Several of the options will
  72.  * make it necessary to have the |stat()| information (the \fB\-l\fP and
  73.  * \fB\-R\fP options, for example), and we will turn on |stateach|
  74.  * later on if any of these are set.
  75.  */
  76. int stateach;
  77.  
  78. /*@ \fILs\fP takes quite a few options: .IP \fB\-l\fP
  79.  * Print in "long listing" format. Sets |flags_l|, unsets |flags_C|.
  80.  * .IP \fB\-g\fP
  81.  * Include the group ownership along with the user ownership in the long
  82.  * format listing. Sets |flags_g|.
  83.  * .IP \fB\-t\fP
  84.  * Sort the listing by the modification time, with most recent times
  85.  * printed first. Sets |flags_t|.
  86.  * .IP \fB\-a\fP
  87.  * Include all files. By default, files whose names begin with "." are not
  88.  * included. Sets |flags_a|.
  89.  * .IP \fB\-A\fP
  90.  * Include all files, even those beginning with ".", except for "." and "..".
  91.  * This flag is automatically turned on for the superuser. Sets |flags_A|.
  92.  * .IP \fB\-s\fP
  93.  * Print the size of the file (in kilobytes) with each file. Sets |flags_s|.
  94.  * .IP \fB\-d\fP
  95.  * List named directories explicitly instead of their contents. Sets
  96.  * |flags_d|.
  97.  * .IP \fB\-r\fP
  98.  * Sort the listing in reverse order. Sets |flags_r|.
  99.  * .IP \fB\-u\fP
  100.  * Use the file access time instead of the modification time in the listings
  101.  * (\fB\-l\fP option) and/or as the sort key (\fB\-t\fP option). Sets
  102.  * |flags_u|. \fI(Currently ineffectual in Minix.)\fP
  103.  * .IP \fB\-c\fP
  104.  * Like \fB\-u\fP, except that the inode change time is used instead.
  105.  * Sets |flags_c|.
  106.  * .IP \fB\-i\fP
  107.  * Print the file's inode number with each file. Sets |flags_i|.
  108.  * .IP \fB\-f\fP
  109.  * Force the named files to be interpreted as directories, whether they
  110.  * are or not. (Actually, the POSIX-type directory routines cause problems
  111.  * with this. They reqire that the file be a directory.) Sets |flags_f|
  112.  * and |flags_a|, and unsets |flags_l|,
  113.  * |flags_t|, |flags_s|, and |flags_r|.
  114.  * .IP \fB\-F\fP
  115.  * After the filenames of directories, print "/". After executable files,
  116.  * print "*". Sets |flags_F|.
  117.  * .IP \fB\-R\fP
  118.  * Recursively print each subdirectory. Sets |flags_R|.
  119.  * .IP \fB\-1\fP
  120.  * Print in "one-column" format instead of columnar format. This is the
  121.  * default if standard output is not a tty. Unsets |flags_C|.
  122.  * .IP \fB\-C\fP
  123.  * Print in columnar format. This is the default if standard output is
  124.  * a tty, provided |ONECOLUMN| has not been defined. Sets |flags_C|.
  125.  */
  126. #define VALID_FLAGS    "lgtaAsdrucifFR1C"
  127.  
  128. int flags_l, flags_g, flags_t, flags_a, flags_A, flags_s, flags_d, flags_r, flags_u, flags_c, flags_i, flags_f, flags_F, flags_R, flags_C;
  129.  
  130. /*@ */
  131. main(argc, argv)
  132. int argc;
  133. char *argv[];
  134. {
  135.   void add_args(     /* int argc; char **argv; */ );
  136.   void listall(     /* void */ );
  137.  
  138.   int c;            /* option character */
  139. #ifdef noperprintf
  140.   noperprintf(stdout);
  141. #endif
  142.  
  143. #ifndef ONECOLUMN
  144.   if (isatty(1)) flags_C = 1;
  145. #endif
  146.  
  147.   while ((c = getopt(argc, argv, VALID_FLAGS)) != EOF) {
  148.     switch (c) {
  149.         case 'l':    flags_l = 1;    break;
  150.         case 'g':    flags_g = 1;    break;
  151.         case 't':    flags_t = 1;    break;
  152.         case 'a':    flags_a = 1;    break;
  153.         case 'A':    flags_A = 1;    break;
  154.         case 's':    flags_s = 1;    break;
  155.         case 'd':    flags_d = 1;    break;
  156.         case 'r':    flags_r = 1;    break;
  157.         case 'u':    flags_u = 1;    break;
  158.         case 'c':    flags_c = 1;    break;
  159.         case 'i':    flags_i = 1;    break;
  160.         case 'f':    flags_f = 1;    break;
  161.         case 'F':    flags_F = 1;    break;
  162.         case 'R':    flags_R = 1;    break;
  163.         case '1':    flags_C = 0;    break;
  164.         case 'C':    flags_C = 1;    break;
  165.  
  166.         case '?':
  167.         fprintf(stderr, "Usage: ls -%s [file ...]\n",
  168.             VALID_FLAGS);
  169.         exit(1);
  170.     }
  171.   }
  172.  
  173.   if (flags_f) {
  174.     flags_l = flags_t = flags_s = flags_r = 0;
  175.     flags_a = 1;
  176.   }
  177.   if (flags_l || flags_s || flags_i) flags_C = 0;
  178.  
  179.   flags_r = flags_r ? -1 : 1;    /* multiplier for comparisons */
  180.  
  181.   if (geteuid() == 0 && !flags_a) flags_A = 1;
  182.  
  183.   stateach = !flags_f;
  184.   add_args(argc - optind + 1, argv + optind - 1);
  185.  
  186.   stateach = !flags_f && (flags_l || flags_t || flags_s || flags_i
  187.             || flags_F || flags_R);
  188.   listall();
  189.  
  190.   exit(0);
  191. }
  192.  
  193. /*@* The files table.
  194.  * The |struct lsfile| structure is the main data structure used by
  195.  * \fIls\fP. The |files| array is an array of these structures, with
  196.  * each entry representing one file to be listed by the program.
  197.  * The |f_stat| field is the result of a |stat()| call on the file, if
  198.  * one has been done. The |f_name| field points to the filename, either
  199.  * directly to the command-line argument, or to a copy in string space
  200.  * of a name read from a directory. The |f_parent| field points to the
  201.  * parent directory of a file, so that the entire relative pathname
  202.  * can be constructed using the |pathname()| function below.
  203.  * .PP
  204.  * There are at most |NFILE| entries in the staticaly-allocated table.
  205.  * Entries are added as a directory is read in, and removed when the
  206.  * listing of that directory is done. The |filep| variable is used to
  207.  * point to the next free entry.
  208.  */
  209. #ifndef NFILE
  210. #define NFILE        512
  211. #endif
  212.  
  213. struct lsfile {
  214.   struct stat f_stat;        /* file information from inode */
  215.   char *f_name;            /* file name */
  216.   struct lsfile *f_parent;    /* parent directory, if any */
  217. };
  218.  
  219. struct lsfile files[NFILE];
  220. struct lsfile *filep = files;
  221.  
  222. /*@ When a directory is sorted, the time spent exchanging entries is reduced
  223.  * by exchanging pointers to entries instead of the entries themselves.
  224.  * When a listing is printed, the file table entries are accessed
  225.  * indirectly through |sortindex| entries.
  226.  */
  227. struct lsfile *sortindex[NFILE];
  228.  
  229.  
  230. /*@ The string area is used to store filenames read in from directories,
  231.  * as well as the lines of output for columnar listings. Like the file
  232.  * table, space in the string area is deallocated when it is no longer
  233.  * needed.
  234.  */
  235. #ifndef STRINGSPACE
  236. #define STRINGSPACE    8192
  237. #endif
  238.  
  239. char strings[STRINGSPACE];
  240. char *stringp = strings;
  241.  
  242. /*@ The |AD